package f.h.dragon.datastructures.bplustree;

/**
 * BplusTree: Tree index mapping Strings to Strings.
 * 
 * @author Wenlong Meng(wenlong.meng@gmail.com)
 * @version 1.0 at 2012/04/27
 * @since 1.0
 */
public class BplusTreeString implements IStringTree {

	// Local variables
	/**
	 * Internal tree mapping Strings to bytes (for conversion to Strings).
	 */
	public ITreeIndex tree;
	/**
	 * default charset name
	 */
	private static String charsetName = "UTF-8";

	// Constructor
	/**
	 * construct BplusTreeString with tree
	 * 
	 * @param tree
	 */
	public BplusTreeString(ITreeIndex tree) {
		this.tree = tree;
	}

	/**
	 * construct BplusTree by BplusTreeBytes, see {@link BplusTreeBytes#initialize(String, String, int, int, int, int)}
	 * 
	 * @param treefileName
	 * @param blockfileName
	 * @param keyLength
	 * @param cultureId
	 * @param nodesize
	 * @param buffersize
	 * @return
	 * @throws Exception
	 */
	public static BplusTreeString initialize(String treefileName,
			String blockfileName, int keyLength, int cultureId, int nodesize,
			int buffersize) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.initialize(treefileName,
				blockfileName, keyLength, cultureId, nodesize, buffersize);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString initialize(String treefileName,
			String blockfileName, int KeyLength, int CultureId)
			throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.initialize(treefileName,
				blockfileName, KeyLength, CultureId);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString initialize(String treefileName,
			String blockfileName, int KeyLength) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.initialize(treefileName,
				blockfileName, KeyLength);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString initialize(java.io.RandomAccessFile treefile,
			java.io.RandomAccessFile blockfile, int KeyLength, int CultureId,
			int nodesize, int buffersize) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.initialize(treefile, blockfile,
				KeyLength, CultureId, nodesize, buffersize);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString initialize(java.io.RandomAccessFile treefile,
			java.io.RandomAccessFile blockfile, int KeyLength, int CultureId)
			throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.initialize(treefile, blockfile,
				KeyLength, CultureId);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString initialize(java.io.RandomAccessFile treefile,
			java.io.RandomAccessFile blockfile, int KeyLength) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.initialize(treefile, blockfile,
				KeyLength);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString reOpen(java.io.RandomAccessFile treefile,
			java.io.RandomAccessFile blockfile) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.reOpen(treefile, blockfile);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString reOpen(String treefileName,
			String blockfileName) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes
				.reOpen(treefileName, blockfileName);
		return new BplusTreeString(tree);
	}

	public static BplusTreeString readOnly(String treefileName,
			String blockfileName) throws Exception {
		BplusTreeBytes tree = BplusTreeBytes.readOnly(treefileName,
				blockfileName);
		return new BplusTreeString(tree);
	}

	// #region ITreeIndex Members

	public void recover(boolean CorrectErrors) throws Exception {
		this.tree.recover(CorrectErrors);
	}

	public void removeKey(String key) throws Exception {
		this.tree.removeKey(key);
	}

	public String firstKey() throws Exception {
		return this.tree.firstKey();
	}

	public String nextKey(String AfterThisKey) throws Exception {
		return this.tree.nextKey(AfterThisKey);
	}

	public boolean containsKey(String key) throws Exception {
		return this.tree.containsKey(key);
	}

	public Object get(String key, Object defaultValue) throws Exception {
		Object test = this.tree.get(key, null);
		if (test != null) {
			return bytesToString((byte[]) test);
		}
		return defaultValue;
	}

	public void set(String key, Object map) throws Exception {
		// if (!(map is String))
		// {
		// throw new
		// BplusTreeException("BplusTree only stores Strings as values");
		// }
		String theString = (String) map;
		byte[] bytes = stringToBytes(theString);
		// this.tree[key] = bytes;
		this.tree.set(key, bytes);
	}

	public void commit() throws Exception {
		this.tree.commit();
	}

	public void abort() throws Exception {
		this.tree.abort();
	}

	public void setFootPrintLimit(int limit) throws Exception {
		this.tree.setFootPrintLimit(limit);
	}

	public void shutdown() throws Exception {
		this.tree.shutdown();
	}

	public int compare(String left, String right) throws Exception {
		return this.tree.compare(left, right);
	}

	// #endregion
	public String get(String key) throws Exception {
		Object theGet = this.tree.get(key, null);
		if (theGet != null) {
			byte[] bytes = (byte[]) theGet;
			return bytesToString(bytes);
		}
		// System.Diagnostics.Debug.WriteLine(this.toHtml());
		throw new BplusTreeKeyMissingException("key not found " + key);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * f.h.dragon.datastructures.bplustree.IStringTree#set(java.lang.String,
	 * java.lang.String)
	 */
	public void set(String key, String value) throws Exception {
		byte[] bytes = stringToBytes(value);
		this.tree.set(key, bytes);
	}

	/**
	 * bytes to string with utf-8
	 * 
	 * @param bytes
	 * @return
	 * @throws Exception
	 */
	public static String bytesToString(byte[] bytes) throws Exception {
		return new String(bytes, 0, bytes.length, charsetName);
	}

	/**
	 * string to bytes with utf-8
	 * 
	 * @param theString
	 * @return
	 * @throws Exception
	 */
	public static byte[] stringToBytes(String theString) throws Exception {
		return theString.getBytes(charsetName);
	}

}
